#include <GL/glew.h>
#include <cave_ogl.h>
#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <map>
#include "opengl_3.h"
#include <mutex>
std::map<int,OpenGLContext> contexts_;
std::mutex map_lock_;

void InitGL()
{
	if (CAVEMasterDisplay()) {
		glewInit();
	}
	CAVEDisplayBarrier();

	std::cerr << "InitGL 0\n";
	{
		std::lock_guard<std::mutex> lock_(map_lock_);
		contexts_.insert(std::pair<int,OpenGLContext>(CAVEUniqueIndex(),OpenGLContext()));
	}
	std::cerr << "InitGL 1\n";
	OpenGLContext& ctx_ = contexts_[CAVEUniqueIndex()];
	std::cerr << "InitGL 2\n";
	ctx_.setupScene();
	std::cerr << "InitGL 3\n";
	if (CAVEMasterDisplay()) {
		

		ctx_.generatePeon();
	}	
	std::cerr << "InitGL 4\n";
	CAVEDisplayBarrier();
	std::cerr << "InitGL 5\n";
}

void DrawGLScene()
{
  // All data should be read only	
	assert(contexts_.find(CAVEUniqueIndex())!=contexts_.end());
	OpenGLContext& ctx_ = contexts_[CAVEUniqueIndex()];
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
	glm::mat4 projection;
	glm::mat4 modelview;
	glGetFloatv(GL_PROJECTION_MATRIX,glm::value_ptr( projection ));
	glGetFloatv(GL_MODELVIEW_MATRIX,glm::value_ptr(modelview));
	

	ctx_.setViewMatrix( modelview );
			 // glm::mat4(1.0,0.0,0.0,0.0, 0.0,1.0,0.0,0.0, 0.0,0.0,1.0,0.0, 0.0, 5, -15,1.0) );
	ctx_.setProjectionMatrix( ( projection ) );

	int idBtn = -1;	   
	for (int i = 0; i < 32; i++) {
          if (CAVEController->button[i] != 0)
            idBtn = i;
          //std::cout << i << " : " << CAVEController->button[i] << std::endl;
        }	
	ctx_.updateCam(idBtn);	


	ctx_.renderScene();
	
}

void FrameFunc()
{
	assert(contexts_.find(CAVEUniqueIndex())!=contexts_.end());
	OpenGLContext& ctx_ = contexts_[CAVEUniqueIndex()];
	if (CAVEMasterDisplay()) {

// P>U 3
// P>L 0
// P>R 2
// P>B 1
	
// DP 4
// DZ 6

//		ctx_.updateCam();
		/*
		 * (int) CAVEController->buttons[32]
		 * (float) CAVEController->valuator[32]   <-1.0; 1.0> 
if (fabs(CAVEController->valuator[0])<0.1) .....
		 * 
		 * 
		 */
		
		ctx_.updatePeon();
		
	}
	CAVEDisplayBarrier();
}

int main(int argc, char **argv) 
{  
	glewInit();
		
	CAVEConfigure(&argc,argv,0);
	CAVEInitApplication((CAVECALLBACK)InitGL,0);
	CAVENear=0.1f;
	CAVEFar=1000.0f;	
		
	CAVEInit();
	
	CAVEFrameFunction((CAVECALLBACK)FrameFunc,0);
	CAVEDisplay((CAVECALLBACK)DrawGLScene,0);
	

	std::cout << "Starting up main loop\n";
 	if (CAVEDistribMaster()) 
		while (!CAVEgetbutton(CAVE_ESCKEY)) {
			CAVEUSleep(10);
		}
	else while (!CAVESync->Quit) CAVEUSleep(15);
	std::cout<< "Cleaning up.\n";
	CAVEExit();
	return 0;
}
